package com.winchain.chainbill.bill.biz.send.service.impl;

import com.shell.bee.base.exception.UnCheckMsgException;
import com.shell.bee.base.utils.JsonUtil;
import com.shell.bee.base.utils.StringUtil;
import com.shell.bee.cache.Cache;
import com.shell.bee.cache.CacheBuilder;
import com.shell.bee.report.excel.ExcelParser;
import com.shell.framework.utils.CommonDataUtil;
import com.winchain.chainbill.bill.base.po.CbOpt;
import com.winchain.chainbill.bill.base.po.CbRec;
import com.winchain.chainbill.bill.base.po.CbSnd;
import com.winchain.chainbill.bill.base.po.CbStats;
import com.winchain.chainbill.bill.biz.BatchSendEvent;
import com.winchain.chainbill.bill.biz.Bill;
import com.winchain.chainbill.bill.biz.BillEvent;
import com.winchain.chainbill.bill.biz.contract.rx.ContractSponsorSubscriber;
import com.winchain.chainbill.bill.biz.send.rx.BillAttSubscriber;
import com.winchain.chainbill.bill.biz.send.rx.BillBatchMsgSubscriber;
import com.winchain.chainbill.bill.biz.send.rx.BillHldrSubscriber;
import com.winchain.chainbill.bill.biz.send.rx.BillMoveSubscriber;
import com.winchain.chainbill.bill.biz.send.rx.BillMsgSubscriber;
import com.winchain.chainbill.bill.biz.send.rx.BillOptSubscriber;
import com.winchain.chainbill.bill.biz.send.rx.BillQuotaSubscriber;
import com.winchain.chainbill.bill.biz.send.rx.BillRecordSubscriber;
import com.winchain.chainbill.bill.biz.send.rx.BillSndSubscriber;
import com.winchain.chainbill.bill.biz.send.rx.BillStatsSubscriber;
import com.winchain.chainbill.bill.biz.send.service.BillCheckService;
import com.winchain.chainbill.bill.biz.send.service.BillImptService;
import com.winchain.chainbill.bill.biz.send.service.BillService;
import com.winchain.chainbill.bill.biz.send.service.BillSndService;
import com.winchain.chainbill.bill.biz.send.vo.BillImpt;
import com.winchain.chainbill.bill.biz.send.vo.ReadEcho;
import java.io.File;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import rx.Observable;

@Service("billSndService")
public class BillSndServiceImpl implements BillSndService {
	@Autowired
	private BillService billService;
	@Autowired
	private BillImptService billImptService;
	@Autowired
	private BillCheckService billCheckService;
	@Autowired
	private BillRecordSubscriber<CbSnd> billRecordSubscriber;
	@Autowired
	private BillOptSubscriber billOptSubscriber;
	@Autowired
	private BillHldrSubscriber billHldrSubscriber;
	@Autowired
	private BillStatsSubscriber billStatsSubscriber;
	@Autowired
	private BillSndSubscriber billSndSubscriber;
	@Autowired
	private BillMoveSubscriber billMoveSubscriber;
	@Autowired
	private BillQuotaSubscriber billQuotaSubscriber;
	@Autowired
	private BillMsgSubscriber billMsgSubscriber;
	@Autowired
	BillBatchMsgSubscriber billBatchMsgSubscriber;
	@Autowired
	BillAttSubscriber billAttSubscriber;
	@Autowired
	private ContractSponsorSubscriber<CbSnd> contractSponsorSubscriber;
	private static final Cache<String, ReadEcho> READECHO_CACHE = CacheBuilder.newBuilder().build();

	public void send(CbRec record, CbSnd send, String remark, String attInvoicesJson, boolean isBatchSend) {
		String msg = this.billCheckService.checkBillSnd(record, send);
		if (StringUtil.notEmpty(msg)) {
			throw new UnCheckMsgException(msg);
		}
		CbStats stats = new CbStats();

		boolean rejectFlag = !StringUtil.emptyAndNull(record.getBillId());
		this.billService.init(record, stats, send);

		CbOpt opt = getSndOpt(record, rejectFlag);
		opt.setRemark(remark);

		Bill<CbSnd> bill = new Bill();

		bill.setStats(stats);
		bill.setSource(send);
		bill.setRec(record);
		BillEvent<CbSnd> event = new BillEvent(bill);
		event.setOperation(opt);
		event.setValue("OwnerId", send.getBuyerId());
		event.setValue("bizId", send.getSndId());

		String contractFileIds = send.getContractFileIds();
		event.setValue("invType", "2");

		event.setValue("contractFileIds", contractFileIds);
		event.setValue("invoiceNo", send.getInvoiceNo());

		event.setValue("attInvoices", attInvoicesJson);
		event.setValue("invType", "2");

		event.setValue("rejectFlag", Boolean.valueOf(rejectFlag));

		Observable<BillEvent<CbSnd>> observers = Observable.just(event);
		observers.subscribe(this.billRecordSubscriber);
		observers.subscribe(this.billOptSubscriber);
		if (!rejectFlag) {
			observers.subscribe(this.billHldrSubscriber);
		}
		observers.subscribe(this.billStatsSubscriber);
		observers.subscribe(this.billSndSubscriber);
		observers.subscribe(this.billMoveSubscriber);
		observers.subscribe(this.billQuotaSubscriber);
		observers.subscribe(this.billAttSubscriber);
		observers.subscribe(this.contractSponsorSubscriber);
		if (!isBatchSend) {
			observers.subscribe(this.billMsgSubscriber);
		}
	}

	private CbOpt getSndOpt(CbRec bill, boolean rejectFlag) {
		CbOpt opt = new CbOpt();
		opt.setCurState(bill.getBillState());
		if (rejectFlag) {
			opt.setOptCode("E102");
		} else {
			opt.setOptCode("E101");
		}
		if ("1".equals(bill.getBillType())) {
			opt.setLimDate(bill.getExpDate());
		} else {
			opt.setLimDate(bill.getSndDate());
		}
		return opt;
	}

	public ReadEcho read(File file, String finId, String finNm) throws Exception {
		List<BillImpt> impts = ExcelParser.parseExcel(file.getPath(), BillImpt.class);
		ReadEcho echo = this.billImptService.checkBillImpt(impts, finId, "");
		if ((StringUtil.emptyAndNull(echo.getError())) && (echo.getData().size() > 0)) {
			READECHO_CACHE.put(getBillImptCacheKey(file.getName()), echo, 120);
		}
		return echo;
	}

	public void impt(File file, String grpId, String finId, String finNm, String invoices, String contracts)
			throws Exception {
		ReadEcho echo = (ReadEcho) READECHO_CACHE.get(getBillImptCacheKey(file.getName()));
		if (echo == null) {
			List<BillImpt> impts = ExcelParser.parseExcel(file.getPath(), BillImpt.class);
			echo = this.billImptService.checkBillImpt(impts, finId, grpId);
		}
		String msg = echo.getError();
		if (StringUtil.notEmpty(msg)) {
			throw new RuntimeException(msg);
		}
		List<BillImpt> impts = echo.getData();
		CbRec record = null;
		CbSnd send = null;
		int count = 0;
		Map<String, String> contractsMap = (Map) JsonUtil.fromJson(contracts, Map.class);
		Map<String, String> map = (Map) JsonUtil.fromJson(invoices, Map.class);
		for (BillImpt impt : impts) {
			record = this.billImptService.getCbRecord(impt);
			send = this.billImptService.getCbSnd(impt);

			record.setGrpId(grpId);
			record.setFinId(finId);
			record.setFinNm(finNm);
			send.setContractFileIds((String) contractsMap.get(String.valueOf(count)));
			send(record, send, null, (String) map.get(String.valueOf(count)), true);
			count++;
		}
		BatchSendEvent event = new BatchSendEvent();
		event.setImpts(impts);
		Observable<BatchSendEvent> observers = Observable.just(event);
		observers.subscribe(this.billBatchMsgSubscriber);
	}

	private String getBillImptCacheKey(String fileName) {
		StringBuffer buffer = new StringBuffer("cr_open");
		buffer.append("-").append(CommonDataUtil.getUserId());
		buffer.append("-").append(fileName);
		return buffer.toString();
	}
}
